# -*- coding: utf-8 -*-

import os
import re
import cv2
import csv
import time
import locale
import qrcode
import win32print
import win32ui
from zeep import Client
from PIL import Image, ImageWin, ImageDraw, ImageFont


'''
此函数通过身份证号码从OA系统的Web服务获取访客信息
url: Web服务的URL。
Client(url): 使用zeep库创建SOAP客户端。
client.bind(...): 绑定到特定的服务和端口。
s.getMessageBycard(...): 调用Web服务方法获取数据。
异常处理: 打印错误并返回错误信息。
'''
def get_oa_information_by_idcard(idcard):
    try:
        url = 'http://172.26.16.180:8080/sys/webservice/ramaxelReviewGetMessageByCardWebService?wsdl'
        # url = 'http://10.2.216.209:8080/sys/webservice/ramaxelReviewGetMessageByCardWebService?wsdl'
        client = Client(url)
        s = client.bind('IRamaxelReviewGetMessageByCardWebServiceService',
                        'IRamaxelReviewGetMessageByCardWebServicePort')
        result = s.getMessageBycard({'fdIDNumber': idcard})
        return result
    except Exception as e:
        print(e)
        return '查询OA接口失败，请联系相关开发人员'


'''
2. check_result_by_time(result, name)
此函数检查从OA系统返回的访客信息是否在允许的时间范围内，并且姓名是否匹配。
pattern: 正则表达式，用于从字符串中提取日期和时间。
re.findall(pattern, ...): 查找所有匹配的日期时间字符串。
time.mktime(...): 将日期时间字符串转换为时间戳。
根据时间和姓名验证访客信息。
'''

def check_result_by_time(result, name):
    message = ''
    pattern = re.compile('\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}')
    for visitor_information in result:
        if visitor_information['desc'] == '返回成功':
            limit_time_list = re.findall(pattern, visitor_information['fdAllowableTime'])
            now_time = time.time()
            locale.setlocale(locale.LC_ALL, '')
            start_time = time.mktime(time.strptime(limit_time_list[0], '%Y-%m-%d %H:%M'))
            end_time = time.mktime(time.strptime(limit_time_list[1], '%Y-%m-%d %H:%M'))
            if start_time <= now_time <= end_time:
                if str(visitor_information['fdIfPass']) != '30':
                    message = '审批状态未完成'
                elif name == visitor_information['fdVisitName'].strip():
                    return visitor_information
                else:
                    message = '身份证姓名和OA上姓名不一致'
                    if message:
                        return message
                    else:
                        return 'OA系统当前时间内未能获取该访客的信息'
    if message:
        return message
    else:
        return 'OA系统当前时间内未能获取该访客的信息'


'''
make_qr(qr_str, save)
此函数生成二维码并保存为图片。
qrcode.QRCode(...): 创建一个二维码生成器。
qr.add_data(qr_str): 添加数据到二维码。
qr.make_image(): 生成二维码图像。
img.save(save): 保存图像到文件
'''

def make_qr(qr_str, save):
    qr = qrcode.QRCode(version=10, error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=4, border=2)
    qr.add_data(qr_str)
    qr.make(fit=True)
    img = qr.make_image()
    img.save(save)


'''
get_qr_code_img(info)
此函数构建二维码的数据字符串，并调用make_qr来生成二维码图片。
构建包含访客信息的字符串。
调用make_qr函数生成二维码并保存。
'''


def get_qr_code_img(info):
    code_str = '\n'.join([
        f'访问地址: {info.fdAllowableRegion if info.fdAllowableRegion else ""}',
        f'来访时间: {info.fdAllowableTime if info.fdAllowableTime else ""}',
        f'身份证号: %s' % re.sub(r"^\d+(?=\d{4}$)", "***", info.fdIDNumber if info.fdIDNumber else ""),
        f'电话: {info.fdPhoneNo if info.fdPhoneNo else ""}',
        f'OA单号: {info.fdNumber if info.fdNumber else ""}'
    ])
    save_path = 'information.png'
    make_qr(code_str, save_path)
    return save_path


'''
image_zoom(img, min_side)
此函数调整图像大小，使其最小边为指定的尺寸，并保持比例。
cv2.resize(...): 调整图像大小。
cv2.copyMakeBorder(...): 添加边框以确保图像尺寸正确。
'''

def image_zoom(img, min_side):
    size = img.shape
    h = size[0]
    w = size[1]
    scale = max(w, h)/float(min_side)
    new_w = int(w/scale)
    new_h = int(h/scale)
    resize_img = cv2.resize(img, (new_w, new_h))
    if new_w % 2 != 0 and new_h % 2 == 0:
        (top, bottom, left, right) = ((min_side-new_h)/2, (min_side-new_h)/2, (min_side-new_w)/2+1, (min_side-new_w)/2)
    elif new_h % 2 != 0 and new_w % 2 == 0:
        (top, bottom, left, right) = ((min_side-new_h)/2+1, (min_side-new_h)/2, (min_side-new_w)/2, (min_side-new_w)/2)
    elif new_h % 2 == 0 and new_w % 2 == 0:
        (top, bottom, left, right) = ((min_side-new_h)/2, (min_side-new_h)/2, (min_side-new_w)/2, (min_side-new_w)/2)
    else:
        (top, bottom, left, right) = ((min_side-new_h)/2+1, (min_side-new_h)/2,
                                      (min_side-new_w)/2+1, (min_side-new_w)/2)

    pad_ima = cv2.copyMakeBorder(resize_img, int(top), int(bottom), int(left), int(right),
                                 cv2.BORDER_CONSTANT, value=(255, 255, 255))
    return pad_ima


'''
get_img(name, sex, img, info)
此函数生成最终的打印图像，包括身份证照片、二维码和文本信息。
Image.open(...): 打开图像文件。
ImageDraw.Draw(...): 创建一个可以在图像上绘制的对象。
draw.text(...): 在图像上绘制文本。
异常处理: 打印错误并返回错误信息。
'''

def get_img(name, sex, img, info):

    try:
        bmp = Image.open(img)
        img_final = Image.new('RGB', (bmp.size[0] + 330, bmp.size[1] + 100), color=(255, 255, 255))
        img_final.paste(bmp, (0, 0, bmp.size[0], bmp.size[1]))
        draw = ImageDraw.Draw(img_final)
        font = ImageFont.truetype(font='思源黑体SourceHanSansCN-Regular.otf', size=21)

        # 二维码侧边文本
        draw.text((bmp.size[0] + 7, bmp.size[1] - 190),
                  f'访客信息：{name}  {sex}', fill=(0, 0, 0), font=font)
        draw.text((bmp.size[0] + 7, bmp.size[1] - 162),
                  '身份证信息：%s' % re.sub(r"^\d+(?=\d{4}$)", "***", info.fdIDNumber if info.fdIDNumber else ""),
                  fill=(0, 0, 0), font=font)
        draw.text((bmp.size[0] + 7, bmp.size[1] - 134),
                  f'联系方式：{info.fdPhoneNo if info.fdPhoneNo else ""}',
                  fill=(0, 0, 0), font=font)
        draw.text((bmp.size[0] + 7, bmp.size[1] - 106),
                  f'被访问人：{info.fdInterviewee if info.fdInterviewee else ""}',
                  fill=(0, 0, 0), font=font)
        draw.text((bmp.size[0] + 7, bmp.size[1] - 78),
                  f'被访问人电话：{info.fdBeiFangRenDianHua if info.fdBeiFangRenDianHua else ""}',
                  fill=(0, 0, 0), font=font)
        draw.text((bmp.size[0] + 7, bmp.size[1] - 50),
                  f'OA单号：{info.fdNumber if info.fdNumber else ""}',
                  fill=(0, 0, 0), font=font)

        # 二维码下方文本
        draw.text((bmp.size[0] - 195, bmp.size[1] + 10),
                  f'来访日期：{info.fdAllowableTime.replace("至", " 至 ") if info.fdAllowableTime else ""}',
                  fill=(0, 0, 0), font=font)

        draw.text((bmp.size[0] - 195, bmp.size[1] + 38),
                  f'允许访问区域：{info.fdAllowableRegion if info.fdAllowableRegion else ""}',
                  fill=(0, 0, 0), font=font)

        text = f'申请类型：{info.fdIfHaveCar if info.fdIfHaveCar else ""}'
        draw.text((bmp.size[0] - 195, bmp.size[1] + 66),
                  text + f' ({info.fdPlateNo if info.fdPlateNo else "车牌号未返回，可能为同行人员"})'
                  if info.fdIfHaveCar == '记忆含车' else text,
                  fill=(0, 0, 0), font=font)

        img_final.save('./code.png')
    except Exception as e:
        print(e)
        return '获取打印图片失败'

    return None

'''
print_img(img)
此函数使用Windows打印机设置来打印图像。
win32print.GetDefaultPrinter(): 获取默认打印机名称。
win32ui.CreateDC(): 创建设备上下文。
ImageWin.Dib(...): 创建设备无关位图。
dib.draw(...): 在打印机设备上下文中绘制图像。
'''
def print_img(img):
    try:
        printer_name = win32print.GetDefaultPrinter()
        hdc = win32ui.CreateDC()
        hdc.CreatePrinterDC(printer_name)
        hdc.StartDoc(img)
        hdc.StartPage()
        bmp_obj = Image.open(img)
        dib = ImageWin.Dib(bmp_obj)
        x1 = 5
        y1 = 60
        x2 = x1 + 485
        y2 = y1 + 285
        dib.draw(hdc.GetHandleOutput(), (x1, y1, x2, y2))
        hdc.EndPage()
        hdc.EndDoc()
        hdc.DeleteDC()
    except Exception as e:
        return f'打印图片失败, 错误信息{e}'

    return None

'''
print_run(name, sex, information)
此函数整合生成二维码、调整图像大小、生成最终打印图像并打印。
调用get_qr_code_img、image_zoom、get_img和print_img
'''

def print_run(name, sex, information):
    try:
        qr_save_path = get_qr_code_img(information)
        im = cv2.imread(qr_save_path)
        image_new = image_zoom(im, 200)
        cv2.imwrite(qr_save_path, image_new)
        message = get_img(name, sex, qr_save_path, information)

    except Exception as f:
        return f'获取二维码失败, 错误信息{f}'
    else:
        try:
            print_img('./code.png')
        except:
            return '打印信息失败'

    return None


'''
create_csv(name, idcard, sex, information)
此函数将访客信息保存到CSV文件中。
检查和创建年份和月份的目录。
使用csv.DictWriter写入CSV文件。
异常处理: 打印错误并返回错误信息。
这个模块提供了从获取信息到处理、显示和打印访客信息的完整流程，适用于需要访客管理的场合。
'''

def create_csv(name, idcard, sex, information):
    field_order = [*('姓名', '性别', '身份证号码', '允许访问区域', '预期来访时间', '实际来访时间', '电话', '车牌号', '被访问人姓名', '被访问人电话')]
    save_main_path = 'D:/save_data'
    year = time.strftime('%Y', time.localtime(time.time()))
    month = time.strftime('%m', time.localtime(time.time()))
    # day = time.strftime('%d', time.localtime(time.time()))
    file_year = os.path.join(save_main_path, year)
    file_month = os.path.join(file_year, month)
    if not os.path.exists(save_main_path):
        os.mkdir(save_main_path)
    if not os.path.exists(file_year):
        os.mkdir(file_year)
    if not os.path.exists(file_month):
        os.mkdir(file_month)
    csv_file_path = os.path.join(file_month, f'data_{year}_{month}.csv')
    try:
        if not os.path.exists(csv_file_path):
            with open(csv_file_path, 'w', encoding='gbk', newline='') as csvfile:
                writer = csv.DictWriter(csvfile, field_order)
                writer.writeheader()
                writer.writerow(dict(
                    zip(field_order, [
                        name, sex, idcard + '\t',
                        str(information['fdAllowableRegion']),
                        str(information['fdAllowableTime']),
                        str(time.strftime('%Y-%m-%d %H:%M', time.localtime())) + '\t',
                        str(information['fdPhoneNo']) + '\t',
                        str(information['fdPlateNo']) + '\t',
                        str(information['fdInterviewee']),
                        str(information['fdBeiFangRenDianHua']) + '\t'
                    ])
                ))
        else:
            with open(csv_file_path, 'a', encoding='gbk', newline='') as csvfile:
                writer = csv.DictWriter(csvfile, field_order)
                writer.writerow(dict(zip(field_order, [
                    name, sex, idcard + '\t',
                    str(information['fdAllowableRegion']),
                    str(information['fdAllowableTime']),
                    str(time.strftime('%Y-%m-%d %H:%M', time.localtime())) + '\t',
                    str(information['fdPhoneNo']) + '\t',
                    str(information['fdPlateNo']) + '\t',
                    str(information['fdInterviewee']),
                    str(information['fdBeiFangRenDianHua']) + '\t'
                ])))
    except Exception as e:
        return f'数据保存失败，可能是路径{csv_file_path}的文件已经被打开{e}\n'

    return None


if __name__ == '__main__':
    pass
